#pragma once
#include <iostream>
#include <functional>
#include <thread>
#include <memory>
#include <mutex>
#include <unistd.h>
#include <sys/eventfd.h>
#include <sys/timerfd.h>

#include "Epoller.hpp"
class EventLoop;

// 定时任务类
using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _task_id;    // 任务id  用于标识任务，让任务可以被找到
    uint32_t _timeout;    // 定时任务的超时时间
    TaskFunc _task_cb;    // 定时器对象要执行的定时任务
    ReleaseFunc _release; // 用于删除timeWheel中保存的任务对象的信息（删除_timers内部信息）
    bool _canceled;       // 任务是否被取消

public:
    TimerTask(uint64_t id, uint32_t timeout, const TaskFunc &task_cb, ReleaseFunc release_cb)
        : _task_id(id), _timeout(timeout), _task_cb(task_cb), _release(release_cb), _canceled(false) {}
    ~TimerTask()
    {
        if (_canceled == false)
        {
            _task_cb();
            _release();
        }
    }
    uint32_t GetTimeout() { return _timeout; }
    void Cancel() { _canceled = true; } // 取消该任务
};

// 时间轮类
class TimerWheel
{
private:
    using WeakTask = std::weak_ptr<TimerTask>;
    using SharedTask = std::shared_ptr<TimerTask>;

    int _tick;     // 秒针
    int _capacity; // 最大延迟时间
    std::vector<std::vector<SharedTask>> _wheel;
    std::unordered_map<uint64_t, WeakTask> _timers;

    EventLoop *_loop;
    int _timerfd; // 定时器描述符
    std::unique_ptr<Channel> _timer_channel;

private:
    void RemoveTimerMap(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
            _timers.erase(id);
    }

    static int CreateTimerFd()
    {
        int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
        if (timerfd < 0)
        {
            std::cerr << "timerfd create fail" << std::endl;
            abort();
        }
        struct itimerspec itime;
        itime.it_value.tv_sec = 3;
        itime.it_value.tv_nsec = 0;
        itime.it_interval.tv_sec = 2;
        itime.it_interval.tv_nsec = 0;

        timerfd_settime(timerfd, 0, &itime, nullptr);
        return timerfd;
    }

    // 读取一次timerfd，同时指针向后走一步
    void OnTime()
    {
        // 读取timerfd
        uint64_t times;
        int ret = read(_timerfd, &times, 8);
        if (ret < 0)
        {
            std::cerr << "read timerfd error" << std::endl;
            abort();
        }

        // 指针后移
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();
    }
    // 添加定时任务
    void TimerAddInLoop(uint64_t id, uint32_t timeout, const TaskFunc &cb)
    {
        SharedTask pt(new TimerTask(id, timeout, cb, std::bind(&TimerWheel::RemoveTimerMap, this, id)));
        int pos = (_tick + timeout) % _capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
    }
    // 延迟定时任务
    void TimerRefreshInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;
        SharedTask pt = it->second.lock(); // lock获取weak_ptr管理的对象对应的share_ptr

        uint32_t timrout = pt->GetTimeout();
        int pos = (_tick + timrout) % _capacity;
        _wheel[pos].push_back(pt);
    }
    // 取消定时任务
    void TimerCancelInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;
        SharedTask pt = it->second.lock();
        pt->Cancel();
    }

public:
    TimerWheel(EventLoop *loop)
        : _tick(0), _capacity(60), _wheel(_capacity), _loop(loop), _timerfd(CreateTimerFd()), _timer_channel(new Channel(_timerfd, _loop))
    {
        _timer_channel->SetReadCallBack(std::bind(&TimerWheel::OnTime, this));
        _timer_channel->EnableRead(); // 启动读事件监控
    }
    // 添加定时任务
    /*定时器中有个_timers成员，定时器信息的操作可能在多线程中运行，因此需要考虑线程安全问题*/
    /*如果不想加锁的话，就把对定时器的所有操作，都放到同一个线程中进行*/
    void TimerAdd(uint64_t id, uint32_t timeout, const TaskFunc &cb);
    // 延迟定时任务
    void TimerRefresh(uint64_t id);
    // 取消定时任务
    void TimerCancel(uint64_t id);
    /*这个接口存在线程安全问题，不能被外界使用者调用，只能在模块内，在对于的EventLoop线程内执行*/
    bool HasTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
            return false;
        return true;
    }
};

class EventLoop
{
private:
    std::thread::id _thread_id;
    int _event_fd;                           // eventfd唤醒IO事件监控有可能导致的阻塞
    std::unique_ptr<Channel> _event_channel; // 用来管理eventfd描述符
    Epoller _epoller;

    using Functor = std::function<void()>;
    std::vector<Functor> _tasks; // 任务池
    std::mutex _mutex;

    TimerWheel _timer_wheel;

    // 执行所有任务池中的任务
    void RunAllTask()
    {
        // 将任务此中的任务交换出来
        std::vector<Functor> functors;
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.swap(functors);
        }
        // 执行任务
        for (auto &task : functors)
            task();
    }
    static int CreateEventfd()
    {
        int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (efd < 0)
        {
            ERR_LOG("eventfd failed");
            abort(); // 异常退出程序
        }
        return efd;
    }
    void ReadEventfd()
    {
        uint64_t res = 0;
        int ret = read(_event_fd, &res, sizeof(res));
        if (ret < 0)
        {
            // 被信号打断 或者 无数据可读
            if (errno == EINTR || errno == EAGAIN)
                return;
            else
            {
                ERR_LOG("read eventfd failed");
                abort();
            }
        }
    }
    void WeakUpEventfd()
    {
        uint64_t val = 1;
        int ret = write(_event_fd, &val, sizeof(val));
        if (ret < 0)
        {
            if (errno == EINTR)
                return;
            else
            {
                ERR_LOG("read eventfd failed");
                abort();
            }
        }
    }

public:
    EventLoop()
        : _thread_id(std::this_thread::get_id()), _event_fd(CreateEventfd()), _event_channel(new Channel(_event_fd, this)), _timer_wheel(this)
    {
        // 给eventfd添加刻度时间回调函数，去读eventfd事件通知次数
        _event_channel->SetReadCallBack(std::bind(&EventLoop::ReadEventfd, this));
        // 启动读事件监控
        _event_channel->EnableRead();
    }

    void Start()
    {
        while(1)
        {
            // 启动事件监控
            std::vector<Channel *> actives;
            _epoller.StartEPoll(&actives);
            // 事件处理
            for (auto &channel : actives)
            {
                channel->HandleEvent();
            }
            // 执行任务
            RunAllTask();
        }
    }
    // 判断当前线程是否是EventLoop对应的线程
    bool IsInLoop()
    {
        return (_thread_id == std::this_thread::get_id());
    }
    void AssertInLoop()
    {
        assert(_thread_id == std::this_thread::get_id());
    }
    // 判断将要执行的任务是否处于当前线程中，如果是则执行，不是则压入队列中
    void RunInLoop(const Functor &cb)
    {
        if (IsInLoop())
            cb();
        else
            QueueInLoop(cb);
    }
    // 将操作压入任务池
    void QueueInLoop(const Functor &cb)
    {
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.push_back(cb);
        }
        // 唤醒有可能因为没有事件就绪，而导致的epoll阻塞
        //(其实就是给eventfd写入一个数据，就可以触发epoll的可读事件就绪)
        WeakUpEventfd();
    }
    // 添加或修改描述符的事件监控
    void UpdateEvent(Channel *channel)
    {
        return _epoller.UpdateEvent(channel);
    }
    // 移除描述符的事件监控
    void RemoveEvent(Channel *channel)
    {
        return _epoller.RemoveEvent(channel);
    }
    void TimerAdd(uint64_t id, uint32_t timeout, const TaskFunc &cb)
    {
        return _timer_wheel.TimerAdd(id, timeout, cb);
    }
    void TimerRefresh(uint64_t id)
    {
        return _timer_wheel.TimerRefresh(id);
    }
    void TimerCancel(uint64_t id)
    {
        return _timer_wheel.TimerCancel(id);
    }
    // 判断是否有该定时任务
    bool HasTimer(uint64_t id)
    {
        return _timer_wheel.HasTimer(id);
    }
};

// class EventLoop
// {
// private:
//     std::thread::id _thread_id;
//     int _event_fd; // eventfd唤醒IO事件监控有可能导致的阻塞
//     std::unique_ptr<Channel> _event_channel; //用来管理eventfd描述符
//     Epoller _epoller;

//     using Functor = std::function<void()>;
//     std::vector<Functor> _tasks; // 任务池
//     std::mutex _mutex;

//     //执行所有任务池中的任务
//     void RunAllTask()
//     {
//         //将任务此中的任务交换出来
//         std::vector<Functor> functors;
//         {
//             std::unique_lock<std::mutex> _lock(_mutex);
//             _tasks.swap(functors);
//         }
//         //执行任务
//         for(auto &task : functors)
//             task();
//     }
//     static int CreateEventfd()
//     {
//         int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
//         if(efd < 0)
//         {
//             ERR_LOG("eventfd failed");
//             abort(); //异常退出程序
//         }
//         return efd;
//     }
//     void ReadEventfd()
//     {
//         uint64_t res = 0;
//         int ret = read(_event_fd, &res, sizeof(res));
//         if(ret < 0)
//         {
//             //被信号打断 或者 无数据可读
//             if(errno == EINTR || errno == EAGAIN) return;
//             else
//             {
//                 ERR_LOG("read eventfd failed");
//                 abort();
//             }
//         }
//     }
//     void WeakUpEventfd()
//     {
//         uint64_t val = 1;
//         int ret = write(_event_fd, &val, sizeof(val));
//         if(ret < 0)
//         {
//             if(errno == EINTR) return;
//             else
//             {
//                 ERR_LOG("read eventfd failed");
//                 abort();
//             }
//         }
//     }

// public:
//     EventLoop()
//         :_thread_id(std::this_thread::get_id())
//         ,_event_fd(CreateEventfd())
//         ,_event_channel(new Channel(_event_fd, this))
//     {
//         //给eventfd添加刻度时间回调函数，去读eventfd事件通知次数
//         _event_channel->SetReadCallBack(std::bind(&EventLoop::ReadEventfd, this));
//         //启动读事件监控
//         _event_channel->EnableRead();
//     }

//     void Start()
//     {
//         //启动事件监控
//         std::vector<Channel *> actives;
//         _epoller.StartEPoll(&actives);
//         //事件处理
//         for(auto &channel : actives)
//         {
//             channel->HandleEvent();
//         }
//         //执行任务
//         RunAllTask();
//     }
//     //判断当前线程是否是EventLoop对应的线程
//     bool IsInLoop()
//     {
//         return (_thread_id == std::this_thread::get_id());
//     }
//     //判断将要执行的任务是否处于当前线程中，如果是则执行，不是则压入队列中
//     void RunInLoop(const Functor &cb)
//     {
//         if(IsInLoop()) cb();
//         else QueueInLoop(cb);
//     }
//     //将操作压入任务池
//     void QueueInLoop(const Functor &cb)
//     {
//         {
//             std::unique_lock<std::mutex> _lock(_mutex);
//             _tasks.push_back(cb);
//         }
//         //唤醒有可能因为没有事件就绪，而导致的epoll阻塞
//         //(其实就是给eventfd写入一个数据，就可以触发epoll的可读事件就绪)
//         WeakUpEventfd();
//     }
//     //添加或修改描述符的事件监控
//     void UpdateEvent(Channel *channel)
//     {
//         return _epoller.UpdateEvent(channel);
//     }
//     //移除描述符的事件监控
//     void RemoveEvent(Channel *channel)
//     {
//         return _epoller.RemoveEvent(channel);
//     }
// };

// Channel类的功能实现
// 移除监控
void Channel::Remove() { return _loop->RemoveEvent(this); }
// 更新监控事件
void Channel::Update() { return _loop->UpdateEvent(this); }

void TimerWheel::TimerAdd(uint64_t id, uint32_t timeout, const TaskFunc &cb)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerAddInLoop, this, id, timeout, cb));
}
// 延迟定时任务
void TimerWheel::TimerRefresh(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerRefreshInLoop, this, id));
}
// 取消定时任务
void TimerWheel::TimerCancel(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerCancelInLoop, this, id));
}